Automatyczne generowanie kodu
=========================

Poczynając od wersji 1.1.2, Yii wyposażone jest w przeglądarkowe narzędzie do generowania kodu *Gii*. Zastępuje ona poprzednie narzędzie do generacji `yiic shell`, które uruchamiane jest z linii poleceń. W tej części opiszemy jak używać Gii i jak rozszerzać Gii by zwiększyć produktywność dewelopmentu.

Używanie Gii
---------

Gii zaimplementowane zostało w postaci modułu i musi być używane wewnątrz istniejącej aplikacji Yii. Aby używać Gii, najpierw modyfikujemy konfigurację aplikacji w następujący sposób:

~~~
[php]
return array(
	......
	'modules'=>array(
		'gii'=>array(
			'class'=>'system.gii.GiiModule',
			'password'=>'wprowadź tutaj hasło',
			// 'ipFilters'=>array(...lista adresów IP...),
			// 'newFileMode'=>0666,
			// 'newDirMode'=>0777,
		),
	),
);
~~~

W powyższym kodzie deklarujemy moduł nazwany `gii` którego klasą jest [GiiModule]. Określamy również hasło dla modułu, które będzie rządane podczas uzyskiwania dostępu do Gii. 

Domyślnie, z powodu bezpieczeństwa, Gii skonfigurowane jest jako dostępne na lokalnym komputerze. Jeśli chcemy udostępnić go dla innych zaufanych komputerów, możemy skonfigurować właściwość [GiiModule::ipFilters] w sposób pokazany w powyższym kodzie.

Ponieważ Gii może generować i zapisywać nowe pliki z kodem w istniejącej aplikacji, musimy się upewnić, że proces serwera ma odpowiednie uprawnienia do tego. Powyższe właściwości [GiiModule::newFileMode] oraz [GiiModule::newDirMode] kontrolują jak nowe pliki i katalogi powinny być wygenerowane.

> Note|Uwaga: Gii jest przewidziane jako narzędzie deweloperskie. Dlatego też, powinno być zainstalowane jedynie na maszynie deweloperskiej. Ponieważ może ono generować nowe skrypty PHP w aplikacji, powinniśmy zwracać dostateczną uwagę na środki bezpieczeństwa (np. hasła, filtry IP).

Możemy uzyskać dostęp do Gii poprzez adres URL `http://hostname/sciezka/do/index.php?r=gii`. Zakładamy, że `http://hostname/sciezka/do/index.php` to URL dostępu do istniejącej aplikacji Yii.

Jeśli istniejąca aplikacjia Yii używa formatu URL `ścieżek` (zobacz [zarządzanie URL-ami](/doc/guide/topics.url)), możemy uzyskać dostęp do Gii poprzez adres URL `http://hostname/sciezka/do/index.php/gii`. Możemy dodać następujący reguły URL na początej istniejących reguł URL:

~~~
[php]
'components'=>array(
	......
	'urlManager'=>array(
		'urlFormat'=>'path',
		'rules'=>array(
			'gii'=>'gii',
			'gii/<controller:\w+>'=>'gii/<controller>',
			'gii/<controller:\w+>/<action:\w+>'=>'gii/<controller>/<action>',
			...dotychczasowe reguły...
		),
	),
)
~~~

Gii dostarczane jest z kilkoma domyślnymi generatorami kodu. Każdy generator kodu jest odpowiedzialny za generowanie określonego typu kodu. Na przykład, generator kontrolera generuje klasę kontrolera wraz z kilkoma skryptami widoków akcji; generator modelu generuje klasę rekordu aktywnego dla określonej tabeli bazy danych.

Kolejne kroki używane podczas generowania wyglądają następująco:

1. Wejdź na stronę generatora;
2. Uzupełnij pola, które określają parametry generacji kodu. Na przykład, aby używać generatora modułu do utworzenia nowego modułu, należy podać ID modułu.
3. Naciśnij przycisk podglądu kodu `Preview`, który zostanie wygenerowany. Pokaże się tabela przedstawiająca listę plików z kodem, które mają zostac wygenerowane. Możesz kliknąć na każdej z pozycji tej listy aby podejrzeć kod.
4. Naciśnij przycisk generuj `Generate` aby wygenerować pliki z kodem;
5. Przejrzyj log po generacji kodu.


Rozszerzanie Gii
-------------

Chociaż domyślne generatory kodu dostarczane z Gii mogą generować bardzo potężny kod, często chcemy dostosować go lub też utworzyć nowy zgodny z naszym gustem i potrzebami. Na przykład, możemy chcieć wygenerować kod, który będzie pisany w naszym ulubionym stylu kodowania lub też możemy chcieć dodać wsparcie dla wielu języków. Wszystko to może zostać zrobione przy użyciu Gii.

Gii może zostać rozszerzone na dwa sposoby: dostosowanie szablonów kodu istniejących generatorów kodu oraz napisanie nowych generatorów kodu.

###Struktura generatora kodu

Generator kodu przechowywany jest w katalogu, którego nazwa jest traktowana jak nazwa generatora. Generator zazwyczaj zawiera następującą zawartość:

~~~
model/                       katalog główny generatora modelu
   ModelCode.php             model kodu używany do generowania kodu
   ModelGenerator.php        kontroler generujący kod
   views/                    zawiera skrypty widoku dla generatora
      index.php              domyślny widok skryptu
   templates/                zawiera zestawy szablonów kodu
      default/               'domyślny' zestaw szablonu kodu
         model.php           szablon kodu do generowania kodu klasy modelu
~~~

###Ścieżka wyszukiwania generatorów

Gii szuka dostępnych generatorów w zestawie katalogów określonych przez właściwość [GiiModule::generatorPaths]. Jeśli potrzebne jest dostosowanie jej, możemy skonfigurować tą właściwość w konfiguracji aplikacji w następujący sposób:

~~~
[php]
return array(
	'modules'=>array(
		'gii'=>array(
			'class'=>'system.gii.GiiModule',
			'generatorPaths'=>array(
				'application.gii',   // alias ścieżki
			),
		),
	),
);
~~~

Powyższa konfiguracja instruuje Gii aby szukać generatorów w katalogu o aliasie `application.gii`, w odróżnieniu  od domyślnej lokalizacji `system.gii.generators`.

Możliwym jest posiadanie dwóch generatorów o tej samej nazwie ale pod różnymi ścieżakami wyszukiwania. W takim przypadku, generator znajdujący się w wyspecyfikowanej wcześnie właściwości [GiiModule::generatorPaths] ma pierwszeństwo.


###Dostosowywanie szablonów kodu

Jest to najprostszy i najczęściej stosowany sposób rozszerzania Gii. Użyjemy przykładu w celu wyjaśnienia jak dostosować kod szablonu. Zakładamy, że chcemy dostoswać kod generowany przez generator modeli.

Najpierw tworzymy katalog o nazwie `protected/gii/model/templates/compact`. Tutaj `model` oznacza, że będziemy *nadpisywać* domyślny generator modelu. `templates/compact` oznacza, że dodamy nowy zestaw szablonów kodu o nazwie `compact`.

Następnie modyfikujemy naszą konfigurację aplikacji dodając `application.gii` do [GiiModule::generatorPaths] jak pokazano w poprzednim akapicie.

Teraz otwórz stronę generowania modelu. Kliknij na polu szablonu kodu `Code Template`. Powinniśmy zobaczyć listę rozwijaną, zawierającą nasz nowo utworzony katalog szablonów `compact`. Jednakże, jeśli wybierzemy ten szablon do generowania kodu, zobaczymy błąd. Dzieje się tak, pownieważ musimy jeszcze umieścić jakikolwiek właściwy plik szablonu kodu w nowym zestawie szablonów `compact`.

Skopiuj plik `framework/gii/generators/model/templates/default/model.php` do `protected/gii/model/templates/compact`. Jeśli spróbujemy ponownie wygenerować szablon `compact` zakończy się to sukcesem. Jednakże kod wygenerowany nie różni się od tego generowanego przez `domyślny` zestaw szablonów.

Nadszedł czas aby wykonać rzeczywista pracę dostosowywania. Otwórz plik `protected/gii/model/templates/compact/model.php` w celu edytowania go. Pamiętaj, że plik ten będzie używane jako skrypt widoku, co oznacza, że może on zawierać deklaracje i wyrażenia PHP. Zmodyfikujmy szablon w taki sposób, że metoda `attributeLabels()` w generowanym kodzie będzie używała `Yii::t()` do tłumaczenia etykiet atrybutów:

~~~
[php]
public function attributeLabels()
{
	return array(
<?php foreach($labels as $name=>$label): ?>
			<?php echo "'$name' => Yii::t('application', '$label'),\n"; ?>
<?php endforeach; ?>
	);
}
~~~

W każdym szablonie kodu możemy uzyskać dostep do pewnych predefiniowanych zmiennych takich jak `$labels` w powyższym przykładzie. Zmienne te są dostarczane przez odpowiednie generatory kodu. Różne generatory kodu mogą dostarczać różne zestawy zmiennych w swoich szablonach kodu. Prześledź uważnie opisy w domyślnym szablonie.


###Tworzenie nowych generatorów

W tej części pokażemy jak utworzyć nowy generator, który może wygenerować nową klasę widżetu.

Najpierw utworzymy katalog o nazwie `protected/gii/widget`. W katalogu tym utworzymy następujące pliki:

* `WidgetGenerator.php`: zawiera klasę kontrolera `WidgetGenerator`. Jest to punkt startowy generatora widżetów.
* `WidgetCode.php`: zawiera klasę modelu `WidgetCode`. Klasa ta zawiera główną logikę generowania kodu.
* `views/index.php`: skrypt widoku pokazujący formularz z polami wejściowymi generatora kodu.
* `templates/default/widget.php`: domyślny kod szablonu do generowania pliku klasy widżetu.


#### Tworzenie `WidgetGenerator.php`

Plik `WidgetGenerator.php` jest maksymalnie prosty. Zwiera on tylko następujący kod:

~~~
[php]
class WidgetGenerator extends CCodeGenerator
{
	public $codeModel='application.gii.widget.WidgetCode';
}
~~~

W powyższym kodzie określamy jedynie to, iż generator będzie używał klasę modelu, której aliasem ścieżki jest `application.gii.widget.WidgetCode`. Klasa `WidgetGenerator` dziedziczy z klasy [CCodeGenerator], która implementuje wiele funkcjonalności włączając w to akcje potrzebne do zarządzania procesem generowania kodu.

#### Tworznie `WidgetCode.php`

Plik `WidgetCode.php` zawiera model klasy `WidgetCode`, który zawiera główną logikę do generowania klasy widżetu opartej na danych wprowadzonych przez użytkownika. W przykładzie tym zakładamy, że jedyną daną jaką rządamy od użytkownika jest nazwa klady widżetu. Nasza klasa `WidgetCode` wygląda następująco:

~~~
[php]
class WidgetCode extends CCodeModel
{
	public $className;

	public function rules()
	{
		return array_merge(parent::rules(), array(
			array('className', 'required'),
			array('className', 'match', 'pattern'=>'/^\w+$/'),			
		));
	}

	public function attributeLabels()
	{
		return array_merge(parent::attributeLabels(), array(
			'className'=>'Nazwa klasy widżetu',
		));
	}

	public function prepare()
	{
		$path=Yii::getPathOfAlias('application.components.' . $this->className) . '.php';
		$code=$this->render($this->templatepath.'/widget.php');

		$this->files[]=new CCodeFile($path, $code);
	}
}
~~~

Klasa `WidgetCode` dziedziczy z [CCodeModel]. Tak jak w zwykłej klasie modelu także w tej możemy zadeklarować reguły `rules()` oraz etykiety atrybutów `attributeLabels()` odpowiednio w celu sprawdzenia danych wprowadzanych przez użytkownika oraz dostarczenia etykiet atrybutów. Zauważ, że klasa bazowa [CCodeModel] definiuje już pewne reguły oraz etykiety atrybutów i powinniśmy połączyć je z naszymi nowymi regułami i etykietami w naszej klasie.

Metoda `prepare()` przygotowuje kod, kóry będzie generowany. Jej głównym zadaniem jest przygotować listę obiektów [CCodeFile], z których każdy reprezentuje plik kodu, który zostanie wygenerowany. W naszym przykładzie musimy jedynie utworzyć obiekt [CCodeFile], który reprezentuje plik klasy widżetu, który zostanie wygenerowany. Nowa klasa widżetu zostanie wygenerowana w katalogu `protected/components`. Wywołujemy metodę [CCodeFile::render] w celu wygenerowania aktualnego kodu. Metoda ta dołącza kod szablonu jako skrypt PHP i zwraca jego zawartość jako wygenerowany kod za pomocą polecenia echo.


#### Tworznie `views/index.php`

Posiadając kontroler (`WidgetGenerator`) i model (`WidgetCode`) naszedł czas aby utworzyć widok `views/index.php`.

~~~
[php]
<h1>Generatow widżetu</h1>

<?php $form=$this->beginWidget('CCodeForm', array('model'=>$model)); ?>

	<div class="row">
		<?php echo $form->labelEx($model,'className'); ?>
		<?php echo $form->textField($model,'className',array('size'=>65)); ?>
		<div class="tooltip">
			Nazwa klasy widżetu musi zawierać jedynie litery i cyfry.
		</div>
		<?php echo $form->error($model,'className'); ?>
	</div>

<?php $this->endWidget(); ?>
~~~

W powyższym przykładzie wyświetlamy przede wszystkim formularz używając widżetu [CCodeForm]. W formularzu tym wyświetlamy pole zbierające dane wprowadzone dla atrybutu `className` klasy `WidgetCode`.

Podczas tworzenia formularza, możemy wykorzystać dwie fajne funkcjonalności dostarczone przez widżet [CCodeForm]. Pierwszą są podpowiedzi. Druga to przyklejone dane wejściowe (ang. sticky inputs).

Jeśli wypróbowałeś jakikolwiek z domyślnych generatorów kodu, zauważyłeś że podczas ustawiania fokusu na danym polu wejściowym, tuż obok pola wyświetli się ładna dla oka podpowiedź. Może to zostać uzystkane w bardzo prosty sposób poprzez napisanie za polem wejściowym tagu `div`, którego klasą CSS jest `tooltip`.

Dla pewnych pól wejściowych możemy chcieć zapamiętać ich ostatnią poprawną wartość tak aby uchronić użytkownika przed kłopotliwym powtarzaniem za każdym razem tych samych wartości podczas używania generatora.  Przykładem jest pole odczytujące nazwę klasy bazowej domyślnego generatora kodu. Te przyklejone pola są początkowo wyświetlane jako podświetlony, statyczny tekst. Jeśli na nim klikniemy, zamieni się on na pole wejściowe pobierające daną wejściową od użytkownika.

W celu zdefiniowana pola wejściowego jako przyklejonego, potrzebujemy zrobić dwie rzeczy.

Najpierw potrzebujemy zadeklarować regułę sprawdzania poprawności `sticky` do odpowiedniego atrybutu modelu. Na przykład, generator domyślnego kontolera posiada następujące reguły deklarujące atrybuty klasy bazowej `baseClass` oraz akcji `actions` jako przyklejone:

~~~
[php]
public function rules()
{
	return array_merge(parent::rules(), array(
		......
		array('baseClass, actions', 'sticky'),
	));
}
~~~

Po drugie, potrzebujemy dodać klasę CSS o nazwie `sticky` do kontenera `div` pola wejściowego w widoku w następujący sposób:

~~~
[php]
<div class="row sticky">
	...pola wejściowe...
</div>
~~~

#### Tworzenie `templates/default/widget.php`

Na koniec tworzymy szablon kodu `templates/default/widget.php`. Tak jak napisaliśmy już wcześniej, jest on używany jako skrypt widoku, który może zawierać wyrażenia i deklaracje PHP. W szablonie kodu możemy zawsze mieć dostęp do zmiennej `$this`, która odnosi się do obiektu modelu kodu. W naszym przykładzie `$this` odnosi się do obiektu `WidgetModel`. To pozwala uzyskać wprowadzoną przez użytkownika nazwę klasy poprzez `$this->className`.

~~~
[php]
<?php echo '<?php'; ?>

class <?php echo $this->className; ?> extends CWidget
{
	public function run()
	{

	}
}
~~~

Na tym kończy się tworzenie nowego generatora kodu. Możemy uzyskać dostęp do tego generatora kodu bezpośrednio poprzez adres URL `http://hostname/sciezka/do/index.php?r=gii/widget`.

<div class="revision">$Id: topics.gii.txt 3223 2011-05-17 23:02:50Z alexander.makarow $</div>